Skip to content

fix(dlv): the advertisement's vault post is a frozen artifact, not a DLVManager derivation - #720

Merged
cryptskii merged 1 commit into
mainfrom
fix/ad-vault-proto-survives-restart
Aug 24, 2026
Merged

fix(dlv): the advertisement's vault post is a frozen artifact, not a DLVManager derivation#720
cryptskii merged 1 commit into
mainfrom
fix/ad-vault-proto-survives-restart

Conversation

@cryptskii

Copy link
Copy Markdown
Collaborator

Problem (owner cleanup step 3 — the restart recovery gap)

route.publishRoutingAdvertisement derived its full VaultPostProto mirror from dlv_manager.create_vault_post. DLVManager vaults are process-lifetime by doctrine (no repopulation from records — that would fabricate values nobody computed), so any restart permanently orphaned every existing vault for advertisement purposes — observed on hardware during the two-device e2e ("Vault not found", vault A8PSGQGZ…, chip task_3deb28ee).

Fix — durable replay, not rehydration

  • dlv.create freezes the exact encoded post bytes onto the vault's record: new amm_vault_records.vault_post_proto column, joining the frozen baseline_state_ccb/baseline_presentation bytes (third instance of the repo's frozen-artifact pattern).
  • The producer runs after finalize_vault applies the creator signature and enforcement + policy_digest are stamped — the earliest point the bytes are final — and is mandatory: a vault whose post cannot be frozen fails at creation, not at first publish.
  • The publisher loads the record once (it already needed it for the presentation digest) and replays the frozen bytes when the caller passes empty; non-empty caller bytes (router-service integrations) are honoured verbatim as before. The DLVManager derive block is deleted, not gated — the handler no longer touches the manager at all, and an empty column fails closed with an error naming the missing producer.
  • Trader-side sufficiency verified from source: route.syncVaultsForPair already rebuilds the full LimboVault from published post bytes (VaultPost::try_fromfrom_vault_post). Reconcile and dlv.composeVault are durable-only, so the ad path was the only owner-restart consumer.
  • CLIENT_DB_SCHEMA_VERSION 6 → 7; beta does not migrate (clean wipe, devices re-onboard).

Regressions

  • the_advertisement_publishes_from_durable_state_after_a_restart — a fresh router (empty DLVManager over the same durable state, head carried over as the persistence codec would) publishes the ad; also pins that the frozen bytes decode as a VaultPostProto naming the vault and carrying the LimboVaultProto.
  • an_empty_frozen_post_refuses_to_publish_instead_of_rederiving — mutation control blanks the column in SQL (the exact pre-cut database state) and requires the refusal to name the missing producer.

Verification

  • cargo test -p dsm_sdk --lib: 1772 passed / 0 failed (7 ignored)
  • cargo check -p dsm_sdk --all-targets clean; make lint green (fmt + clippy + frontend)
  • Next: owner step 4 — the restart-in-the-middle two-phone run (fresh APK required: schema v7 wipes device state)

…DLVManager derivation

route.publishRoutingAdvertisement derived its VaultPostProto mirror from
dlv_manager.create_vault_post — process-lifetime state — so a restarted
owner could never advertise a vault it had already created and funded
('Vault not found' on hardware during the two-device e2e). DLVManager
doctrine forbids repopulating the manager from records, and this fix
does not: dlv.create now freezes the exact encoded post bytes onto the
vault's record (amm_vault_records.vault_post_proto, joining the frozen
baseline_state_ccb/baseline_presentation bytes), and the publisher
replays them verbatim. The in-memory derive path is deleted, not gated.

The bytes are final only after finalize_vault applies the creator
signature and dlv.create stamps enforcement + policy_digest, so the
producer runs exactly there and is MANDATORY: a vault whose post cannot
be frozen fails at creation, not at first publish. The publisher fails
closed on an empty column with an error naming the missing producer.

Trader-side sufficiency verified from source: route.syncVaultsForPair
already rebuilds the full LimboVault from published post bytes
(VaultPost::try_from -> from_vault_post). Reconcile and dlv.composeVault
are durable-only, so the ad path was the only owner-restart consumer.

CLIENT_DB_SCHEMA_VERSION 6 -> 7; beta does not migrate (clean wipe).

Regressions: a fresh router (empty DLVManager over the same durable
state and carried-over head) publishes the ad — the exact hardware
failure shape; a mutation control blanks the column in SQL (the true
pre-cut database state) and requires the named refusal. dsm_sdk lib
1772/0; make lint green.
@cryptskii
cryptskii merged commit 5a18b34 into main Aug 24, 2026
15 checks passed
@cryptskii
cryptskii deleted the fix/ad-vault-proto-survives-restart branch August 24, 2026 07:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant